package com.app.service.impl;

import com.app.domain.bo.MenuBo;
import com.app.domain.page.Page;
import com.app.domain.po.MenuPo;
import com.app.domain.vo.MenuVo;
import com.app.framework.utils.CoBeanUtils;
import com.app.framework.utils.CollectionUtils;
import com.app.framework.utils.StringsUtils;
import com.app.mapper.MenuMapper;
import com.app.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;

/**
 * 菜单方法实现
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuPo> implements MenuService {

    /**
     * 菜单列表
     */
    @Override
    @Cacheable(cacheNames = "menu", key = "#bo.getPageNum")
    public Page<MenuVo> lists(MenuBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        //获取父级菜单
        List<MenuVo> allParentMenuVos = baseMapper.selectAllParent(0L);
        if (CollectionUtils.isEmpty(allParentMenuVos)) {
            return Page.restPage(new ArrayList<>());
        }
        //获取全部子菜单
        List<MenuVo> allSubMenuVo = baseMapper.selectAllChildren();
        for (MenuVo menuVo : allParentMenuVos) {
            //返回主菜单的子菜单
            List<MenuVo> menus = recursiveChildren(allSubMenuVo, menuVo.getId());
            menuVo.setChildren(menus);
        }
        return Page.restPage(allParentMenuVos);
    }

    /**
     * 菜单详情
     *
     * @param menuId 菜单id
     */
    @Override
    @Cacheable(cacheNames = "menu_details", key = "#menuId")
    public MenuVo details(Long menuId) {
        MenuPo menuPo = baseMapper.selectById(menuId);
        Assert.notNull(menuPo, "该菜单不存在");
        return CoBeanUtils.copy(menuPo, MenuVo.class);
    }

    /**
     * 添加菜单
     *
     * @param bo 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {"menu", "menu_details"}, allEntries = true)
    public void saveOne(MenuBo bo) {
        MenuPo menuPo = CoBeanUtils.copy(bo, MenuPo.class);
        menuPo.setCreateTime(new Date());
        baseMapper.insert(menuPo);
    }

    /**
     * 修改菜单
     *
     * @param bo 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {"menu", "menu_details"}, allEntries = true)
    public void updateOne(MenuBo bo) {
        MenuPo menuPo = baseMapper.selectById(bo.getId());
        Assert.notNull(menuPo, "该菜单不存在");
        CoBeanUtils.copyProperties(bo, menuPo);
        menuPo.setUpdateTime(new Date());
        baseMapper.updateById(menuPo);
    }

    /**
     * 删除菜单
     *
     * @param menuId 菜单ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = {"menu", "menu_details"}, allEntries = true)
    public void deleteOne(Long menuId) {
        MenuPo menuPo = baseMapper.selectById(menuId);
        Assert.notNull(menuPo, "菜单不存在");
        Integer count = baseMapper.selectArticleCountByMenuId(menuId);
        Assert.state(count == 0, "该菜单下有内容,不能删除!");
        //递归删除子菜单
        List<Long> menuIds = new ArrayList<>();
        menuIds.add(menuId);
        collectMenuIds(menuId, menuIds);
        baseMapper.deleteBatchIds(menuIds);
    }

    //--------------------------------------------------------------|↓|公共方法|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|公共方法|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|公共方法|↓|-----------------------------------------------------------------

    /**
     * 获取菜单Map
     *
     * @param menuIds 菜单ID集合
     */
    @Override
    public Map<Long, MenuVo> getMenuMap(List<Long> menuIds) {
        Map<Long, MenuVo> menuMap = new HashMap<>();
        if (CollectionUtils.isEmpty(menuIds)) {
            return menuMap;
        }
        List<Long> uniqueMenuIds = StringsUtils.deduplication(menuIds);
        List<MenuPo> menuPos = baseMapper.selectBatchIds(uniqueMenuIds);
        List<MenuVo> menuVos = CoBeanUtils.copyList(menuPos, MenuVo.class);
        for (MenuVo menuVo : menuVos) {
            menuMap.put(menuVo.getId(), menuVo);
        }
        return menuMap;
    }

    /**
     * 递归删除菜单
     *
     * @param parentId 父级ID
     * @param menuIds  菜单ID集合
     */
    private void collectMenuIds(Long parentId, List<Long> menuIds) {
        List<MenuVo> menuVos = baseMapper.selectAllParent(parentId);
        for (MenuVo menuVo : menuVos) {
            menuIds.add(menuVo.getId());
            collectMenuIds(menuVo.getId(), menuIds);
        }
    }

    /**
     * 递归菜单
     *
     * @param menuVos 菜单集合
     * @param menuId  菜单ID
     */
    public List<MenuVo> recursiveChildren(List<MenuVo> menuVos, Long menuId) {
        List<MenuVo> vos = new ArrayList<>();
        for (MenuVo menuVo : menuVos) {
            if (menuVo.getPid().equals(menuId)) {
                List<MenuVo> vo = recursiveChildren(menuVos, menuVo.getId());
                menuVo.setChildren(vo);
                vos.add(menuVo);
            }
        }
        return vos;
    }

}